<?php

namespace Comment;

use W3\Pager;
use Base\Comments;
use W3\Router;

/**
 * 评论归档组件
 *
 * @author edikud
 * @date 2022/10/22
 * @copyright Copyright (c) 2022 W3 (http://www.mcooo.com)
 * @license GNU General Public License 2.0
 */

class Rows extends Comments
{
    /**
     * 当前页
     *
     * @access private
     * @var integer
     */
    private $currentPage;

    /**
     * 所有文章个数
     *
     * @access private
     * @var integer
     */
    private $total = false;
	
    /**
     * 子父级评论关系
     *
     * @access private
     * @var array
     */
    private $threadedComments = [];

    /**
     * 初始化
     *
     * @access protected
     * @return void
     */
    protected function init()
    {
        $this->parameter([

			# 设置主体
			'main' => 'comment.rows',
			
			# 默认变量数据
		    'parentId' => 0,
		    'commentPage' => 0,
		    'commentsNum' => 0,
		    'allowComment' => 1,
			'pageSize' => $this->config->commentsPageSize,
            'parentRow' => [],
            'respondId' => '',
            'before' =>  '<ol class="comment-list">',
            'after' =>  '</ol>',
            'dateFormat' =>  '',
			'waitingWord' => __('您的评论正等待审核!'),
			
		], true);


        /**
         * 输出分页
         *
         * @param array $template 展现配置信息
         * @return void
         */
        \add_action( 'call@pagination' , function ($widget, $template = [], $echo = true) 
		{
			if(is_bool($template)){
				$echo = $template;
				$template = [];
			}
			
            extract($widget->parameter->many('page', 'pageSize', 'total', 'pageUrl'));

            if (!$widget->config->commentsPageBreak || $total <= $pageSize) return;
			
            $result = Pager::make($page, $pageSize, $total, $pageUrl)
			    ->config($template)
				->html();
				
            if ($echo) {
                echo $result;
            } else {
                return $result;
            }
        });

    }

    /**
     * 评论回调函数
     * 
     * @access private
     * @return void
     */
    private function threadedCommentsCallback()
    {
        if (function_exists('threadedComments')) {
            return threadedComments($this);
        }
        
        $commentClass = '';
        if ($this->uid) {
            if ($this->uid == $this->ownerId) {
                $commentClass .= ' comment-by-author';
            } else {
                $commentClass .= ' comment-by-user';
            }
        }
?>
<li id="<?php $this->theId(); ?>" class="comment-body<?php
    if ($this->levels > 0) {
        echo ' comment-child';
        $this->levelsAlt(' comment-level-odd', ' comment-level-even');
    } else {
        echo ' comment-parent';
    }
    $this->alt(' comment-odd', ' comment-even');
    echo $commentClass;
?>">
    <div class="comment-author" >
        <span><a href="<?php $this->author->permalink(); ?>"><img src="<?php $this->author->avatar(); ?>" width="32" height="32" alt="<?php $this->author->name(); ?>"></a></span>
        <cite class="fn" ><?php $this->author->name(); ?></cite>
    </div>
    <div class="comment-meta">
        <a href="<?php $this->permalink(); ?>"><time datetime="<?php $this->date('c'); ?>"><?php $this->date($this->parameter->dateFormat); ?></time></a>
        <?php if ('waiting' == $this->status) { ?>
            <em class="comment-awaiting-moderation"><?php $this->parameter->waitingWord(); ?></em>
        <?php } ?>
    </div>
    <div class="comment-content" >
    <?php $this->content(); ?>
    </div>
    <div class="comment-reply">
        <?php $this->reply(); ?>
    </div>
    <?php if ($this->children) { ?>
    <div class="comment-children">
        <?php $this->threadedComments(); ?>
    </div>
    <?php } ?>
</li>
<?php
    }
    
    /**
     * 获取当前评论链接
     *
     * @access protected
     * @return string
     */
    protected function ___permalink(): string
    {

        if ($this->config->commentsPageBreak) {            
            $pageRow = ['permalink' => $this->parentRow['pathinfo'], 'commentPage' => $this->currentPage];
            return Router::buildUrl('comment_page',
                        $pageRow) . '#' . $this->theId;
        }
        
        return $this->parentRow['permalink'] . '#' . $this->theId;
    }

    /**
     * 子评论
     *
     * @access protected
     * @return array
     */
    protected function ___children(): array
    {
        return $this->config->commentsThreaded && !$this->isTopLevel && isset($this->threadedComments[$this->coid]) 
            ? $this->threadedComments[$this->coid] : [];
    }

    /**
     * 是否到达顶层
     *
     * @access protected
     * @return boolean
     */
    protected function ___isTopLevel(): bool
    {
        return $this->levels > $this->config->commentsMaxNestingLevels - 2;
    }

    /**
     * 重载内容获取
     *
     * @access protected
     * @return void
     */
    protected function ___parentRow(): ?array
    {
        return $this->parameter->parentRow;
    }

    /**
     * 输出文章评论数
     *
     * @param ...$args
     */
    public function num(...$args)
    {
        if (empty($args)) {
            $args[] = '%d';
        }

        $num = intval($this->total);

        echo sprintf($args[$num] ?? array_pop($args), $num);
    }

    /**
     * 执行函数
     *
     * @access public
     * @return void
     */
    public function execute()
    {
        if (!$this->parameter->parentId) {
            return;
        }

        $select = $this->db->select()
		    ->from('table.comments')
			->where('table.comments.cid = ?', $this->parameter->parentId);
			
		if($this->auth->hasLogin()){
			
			$select->where('table.comments.status = ? OR (table.comments.uid = ?  AND table.comments.status = ?)', 'approved', $this->auth->uid, 'waiting');

		} else {
			
			$select->where('table.comments.status = ? ', 'approved');
		}

        $select
		    ->order('table.comments.coid', 'ASC')
            ->get([$this, 'push']);
        
        /** 需要输出的评论列表 */
        $outputComments = [];
        
        /** 如果开启评论回复 */
        if ($this->config->commentsThreaded) {
        
            foreach ($this->stack as $coid => &$comment) {
                
                /** 取出父节点 */
                $parent = $comment['parent'];
            
                /** 如果存在父节点 */
                if (0 != $parent && isset($this->stack[$parent])) {
                
                    /** 如果当前节点深度大于最大深度, 则将其挂接在父节点上 */
                    if ($comment['levels'] >= $this->config->commentsMaxNestingLevels) {
                        $comment['levels'] = $this->stack[$parent]['levels'];
                        $parent = $this->stack[$parent]['parent'];     // 上上层节点
                        $comment['parent'] = $parent;
                    }
                
                    /** 计算子节点顺序 */
                    $comment['order'] = isset($this->threadedComments[$parent]) 
                        ? count($this->threadedComments[$parent]) + 1 : 1;
                
                    /** 如果是子节点 */
                    $this->threadedComments[$parent][$coid] = $comment;
                } else {
                    $outputComments[$coid] = $comment;
                }
                
            }
        
            $this->stack = $outputComments;
        }
        
        /** 评论排序 */
        if ('DESC' == $this->config->commentsOrder) {
            $this->stack = array_reverse($this->stack, true);
            $this->threadedComments = array_map('array_reverse', $this->threadedComments);
        }
        
        /** 评论总数 */
        $this->total = count($this->stack);
        
        /** 对评论进行分页 */
        if ($this->config->commentsPageBreak) {
            if ('last' == $this->config->commentsPageDisplay && !$this->parameter->commentPage) {
                $this->currentPage = ceil($this->total / $this->config->commentsPageSize);
            } else {
                $this->currentPage = $this->parameter->commentPage ? $this->parameter->commentPage : 1;
            }
            
            /** 截取评论 */
            $this->stack = array_slice($this->stack,
                ($this->currentPage - 1) * $this->config->commentsPageSize, $this->config->commentsPageSize);
			
            /** 评论置位 */
            $this->length = count($this->stack);
            $this->row = $this->length > 0 ? current($this->stack) : [];
        }
        
        reset($this->stack);
		
		$this->parameter([
		    
			# 当前页数
			'page' => $this->currentPage,
			
			# 内容总数
			'total' => $this->total,
			
			# 页面Url
			'pageUrl' => Router::buildUrl('comment_page', ['permalink'=>$this->parentRow['pathinfo'], 'commentPage'=>'%page%']) . '#comments'
			
		], true);
    }

    /**
     * 将每行的值压入堆栈
     *
     * @access public
     * @param array $value 每行的值
     * @return array
     */
    public function push(array $value): array
    {
        $value = $this->filter($value);
        
        /** 计算深度 */
        if (0 != $value['parent'] && isset($this->stack[$value['parent']]['levels'])) {
            $value['levels'] = $this->stack[$value['parent']]['levels'] + 1;
        } else {
            $value['levels'] = 0;
        }

        /** 重载push函数,使用coid作为数组键值,便于索引 */
        $this->stack[$value['coid']] = $value;
        $this->length ++;
        
        return $value;
    }

    /**
     * 递归输出评论
     *
     * @access protected
     * @return void
     */
    public function threadedComments()
    {
        $children = $this->children;
        if ($children) {
            //缓存变量便于还原
            $tmp = $this->row;
            $this->sequence ++;

            //在子评论之前输出
            echo $this->parameter->before;

            foreach ($children as $child) {
                $this->row = $child;
                $this->threadedCommentsCallback();
                $this->row = $tmp;
            }

            //在子评论之后输出
            echo $this->parameter->after;

            $this->sequence --;
        }
    }
    
    /**
     * 列出评论
     * 
     * @access private
     * @param mixed $options 自定义选项
     * @return void
     */
    public function listComments($options = NULL)
    {
		$this->parameter->merge($options);

        if ($this->have()) { 
            echo $this->parameter->before;
            
            while ($this->next()) {
                $this->threadedCommentsCallback();
            }
            
            echo $this->parameter->after;
        }
    }
    
    /**
     * 根据深度余数输出
     *
     * @param mixed ...$args 需要输出的值
     */
    public function levelsAlt(...$args)
    {
        $num = count($args);
        $split = $this->levels % $num;
        echo $args[(0 == $split ? $num : $split) - 1];
    }

    /**
     * 重载alt函数,以适应多级评论
     *
     * @param ...$args
     */
    public function alt(...$args)
    {
        $num = count($args);

        $sequence = $this->levels <= 0 ? $this->sequence : $this->order;

        $split = $sequence % $num;
        echo $args[(0 == $split ? $num : $split) - 1];
    }

    /**
     * 评论回复链接
     * 
     * @access public
     * @param string $word 回复链接文字
     * @return void
     */
    public function reply($word = '')
    {
        if ($this->config->commentsThreaded && !$this->isTopLevel && $this->parameter->allowComment) {
            $word = empty($word) ? __('回复') : $word;

			/** 插件接口 */
			if(\action_exists('reply')){
				
				echo \do_action('reply', $this, false, $word);
				
			}else{
                echo '<a href="' . substr($this->permalink, 0, - strlen($this->theId) - 1) . '?replyTo=' . $this->coid .
                    '#' . $this->parameter->respondId . '" rel="nofollow" onclick="return comment.reply(\'' .
                    $this->theId . '\', ' . $this->coid . ');">' . $word . '</a>';
			}

        }
    }
    
    /**
     * 取消评论回复链接
     * 
     * @access public
     * @param string $word 取消回复链接文字
     * @return void
     */
    public function cancelReply($word = '')
    {
        if ($this->config->commentsThreaded) {
            $word = empty($word) ? __('取消回复') : $word;

			/** 插件接口 */
			if(\action_exists('cancel_reply')){
				
				echo \do_action('cancel_reply', $this, false, $word);
				
			}else{
				
                $replyId = $this->request->filter('int')->replyTo;
                echo '<a id="cancel-comment-reply-link" href="' . $this->parameter->parentRow['permalink'] . '#' . $this->parameter->respondId .
                '" rel="nofollow"' . ($replyId ? '' : ' style="display:none"') . ' onclick="return comment.cancelReply();">' . $word . '</a>';
			}
        }
    }
}
